package com.ddwl.funds.service;

import com.ddwl.schema.vo.funds.ByteDanceOrderVo;
import org.springframework.util.CollectionUtils;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ddwl.common.constant.*;
import com.ddwl.common.exception.ParamException;
import com.ddwl.schema.bo.funds.FundsPaymentBo;
import com.ddwl.schema.bo.funds.OrderRefundCreBo;
import com.ddwl.schema.bo.funds.PayOrderCreBo;
import com.ddwl.schema.vo.funds.OrderPaymentVo;
import com.ddwl.schema.vo.funds.OrderRefundsVo;
import com.ddwl.common.service.RedisService;
import com.ddwl.common.util.BeanConverUtils;
import com.ddwl.common.util.UUIDGenerator;
import com.ddwl.funds.dao.OrderPayDao;
import com.ddwl.funds.dao.OrderRefundsDao;
import com.ddwl.funds.dao.model.OrderPay;
import com.ddwl.funds.dao.model.OrderRefunds;
import com.ddwl.funds.dao.model.OrderWxPay;
import com.ddwl.schema.bo.funds.OrderPayBo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * 类OrderPayServer.java的实现描述：订单支付处理
 *
 * @author zach
 * @Date :2020-06-02 17:11.
 */
@Slf4j
@Service
public class PaymentServer {

    @Resource
    private OrderPayDao orderPayDao;
    @Resource
    private AliPayServer aliPayServer;
    @Resource
    private OrderRefundsDao orderRefundsDao;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private WxPayServer wxPayServer;
    @Resource
    private RedisService redisService;
    @Resource
    private ByteDanceServer byteDanceServer;


    /**
     * 创建预支付订单
     * @param payOrderCreBo
     * @return
     */
    public OrderPay createOrderPay(PayOrderCreBo payOrderCreBo){
        OrderPay orderPay = orderPayDao.getOrderPay(payOrderCreBo.getOrderId(),payOrderCreBo.getPhaseId(),payOrderCreBo.getProduct());
        if(orderPay!=null){
            return orderPay;
        }
        orderPay = BeanConverUtils.convertBean(payOrderCreBo,OrderPay.class);
        orderPay.setAmount(payOrderCreBo.getTotalAmount());
        orderPay.setTradeStatus(OrderEnum.PayStatus.CRE.getCode());
        orderPay.setReAmount(BigDecimal.ZERO);
        orderPay.setSubject(OrderTypeEnum.getOrderNameByCode(payOrderCreBo.getOrderType()));
        orderPay.setPayTimes(0);
        orderPay.setIsMerge("0");
        orderPayDao.insert(orderPay);
        return orderPay;
    }

    /**
     * 创建支付订单
     * @param orderPayBo
     * @return
     */
    private OrderPay createOrderPay(OrderPayBo orderPayBo){
        OrderPay orderPay = BeanConverUtils.convertBean(orderPayBo,OrderPay.class);
        orderPay.setAmount(orderPayBo.getTotalAmount());
        orderPay.setTradeStatus(OrderEnum.PayStatus.CRE.getCode());
        orderPay.setPayType(orderPayBo.getPaymentType());
        orderPay.setReAmount(BigDecimal.ZERO);
        orderPay.setSubject(OrderTypeEnum.getOrderNameByCode(orderPayBo.getOrderType()));
        orderPay.setExpirationTime(orderPayBo.getExpirationTime());
        orderPay.setPayTimes(0);
        orderPay.setIsMerge("0");
        orderPayDao.insert(orderPay);
        return orderPay;
    }


    /**
     * 创建合并支付订单
     * @param orderPays
     * @return
     */
    public OrderPaymentVo createOrderPay(List<OrderPay>  orderPays){
        OrderPay orderPay = orderPays.get(0);
        orderPay.setAmount(orderPays.stream().map(OrderPay::getAmount).reduce(BigDecimal::add).get());
        orderPay.setTradeStatus(OrderEnum.PayStatus.CRE.getCode());
        orderPay.setReAmount(BigDecimal.ZERO);
        orderPay.setPayTimes(0);
        orderPay.setMasterOrderId(orderPay.getMasterOrderId());
        orderPay.setOrderId(orderPay.getMasterOrderId());
        orderPay.setIsMerge("1");
        orderPay.setId(UUIDGenerator.getShortUUID());
        orderPayDao.insert(orderPay);
        return BeanConverUtils.convertBean(orderPay, OrderPaymentVo.class);
    }

    /**
     * 查询订单详情
     * @param orderId
     * @return
     */
    public OrderPaymentVo getOrderPay(String orderId){
        OrderPay orderPay = orderPayDao.getOrderPayByOrderId(orderId);
        return BeanConverUtils.convertBean(orderPay, OrderPaymentVo.class);
    }



    /**
     * 创建退款订单
     * @param creBo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public OrderRefundsVo createRefunds(OrderRefundCreBo creBo){
        OrderRefunds orderRefunds = orderRefundsDao.getOrderRefundsByBizRefundsNo(creBo.getOrderId(),creBo.getBizRefundsNo());
        if(orderRefunds!=null&&OrderEnum.PayStatus.SUCCEED.getCode().equals(orderRefunds.getStatus())){
            return BeanConverUtils.convertBean(orderRefunds,OrderRefundsVo.class);
        }
        OrderPay orderPay = null;
        if(StrUtil.isNotBlank(creBo.getTradeNo())){
            orderPay = orderPayDao.getOrderPayByTradeNo(creBo.getTradeNo());
        }
        if(orderPay==null&& StrUtil.isNotBlank(creBo.getFundsPayId())){
            orderPay = orderPayDao.selectByPrimaryKey(creBo.getFundsPayId());
        }
        if(orderPay==null){
            orderPay = orderPayDao.getOrderPayByOrderId(creBo.getOrderId());
        }
        ParamException.isNull(orderPay, "为找到该订单号 orderId={},tradeNo={},fundsPayId={}",creBo.getOrderId(),creBo.getTradeNo(),creBo.getFundsPayId());
        ParamException.isFalse(OrderEnum.PayStatus.SUCCEED.getCode().equals(orderPay.getTradeStatus()), "该订单还未完成付款无法申请退款");
        ParamException.isTrue(orderPay.getReAmount().add(creBo.getRefundAmount()).compareTo(orderPay.getAmount())>0,"退款金额超过订单上限");
        orderRefunds = new OrderRefunds();
        orderRefunds.setOrderNo(orderPay.getOrderId());
        orderRefunds.setOrderType(orderPay.getOrderType());
        orderRefunds.setOrderAmount(orderPay.getAmount());
        orderRefunds.setRefundsAmount(creBo.getRefundAmount());
        orderRefunds.setProduct(orderPay.getProduct());
        orderRefunds.setUserId(orderPay.getUserId());
        orderRefunds.setUserName(orderPay.getUserName());
        orderRefunds.setStatus(OrderEnum.PayStatus.CRE.getCode());
        orderRefunds.setOperatorId(creBo.getOperatorId());
        orderRefunds.setPayTradeNo(orderPay.getTradeNo());
        orderRefunds.setOperatorName(creBo.getOperatorName());
        orderRefunds.setBizRefundsNo(creBo.getBizRefundsNo());
        orderRefunds.setNotifyMethod(creBo.getNotifyMethod());
        orderRefunds.setRefundsType(orderPay.getPayType());
        orderRefunds.setPayFlowId(orderPay.getPayFlowId());
        orderRefunds.setPayAppId(orderPay.getPayAppId());
        orderRefundsDao.insert(orderRefunds);
        if(PaymentEnum.WX.getCode().equals(orderRefunds.getRefundsType())){
            wxPayServer.refunds(orderRefunds);
        }else if(PaymentEnum.ALI_PAY.getCode().equals(orderRefunds.getRefundsType())){
            aliPayServer.refunds(orderRefunds);
        }else{
            byteDanceServer.refunds(orderRefunds);
        }
        return BeanConverUtils.convertBean(orderRefunds,OrderRefundsVo.class);
    }

    /**
     * 查询退款订单详情
     * @param bizRefundsNo
     * @return
     */
    public OrderRefundsVo getRefunds(String bizRefundsNo) {
        OrderRefunds orderRefunds = orderRefundsDao.getOrderRefundsByBizRefundsNo(bizRefundsNo);
        return BeanConverUtils.convertBean(orderRefunds, OrderRefundsVo.class);
    }

    /**
     * 查询订单并通知业务
     * @param bizRefundsNo
     * @return
     */
    public OrderRefundsVo getRefundNotify(String bizRefundsNo) {
        OrderRefunds orderRefunds = orderRefundsDao.getOrderRefundsByBizRefundsNo(bizRefundsNo);
        if(OrderEnum.PayStatus.SUCCEED.getCode().equals(orderRefunds.getStatus())){
            if(StrUtil.isNotBlank(orderRefunds.getNotifyMethod())){
                rabbitTemplate.convertAndSend(orderRefunds.getNotifyMethod(),JSON.toJSONString(orderRefunds));
            }
        }else {
            if(PaymentEnum.WX.getCode().equals(orderRefunds.getRefundsType())){
                wxPayServer.queryRefunds(orderRefunds);
            }else if(PaymentEnum.ALI_PAY.getCode().equals(orderRefunds.getRefundsType())){
                aliPayServer.queryRefund(orderRefunds);
            }else{
                byteDanceServer.queryRefund(orderRefunds);
            }
        }
        return BeanConverUtils.convertBean(orderRefunds, OrderRefundsVo.class);
    }

    /**
     * 退款完成
     * @param transactionId
     */
    public void completeRefunds(String refundsId, String transactionId,String flowId){
        OrderRefunds refunds = orderRefundsDao.selectByPrimaryKey(refundsId);
        ParamException.isNull(refunds,"未找到相关付款单");
    //    ParamException.isTrue(OrderEnum.PayStatus.SUCCEED.getCode().equals(refunds.getStatus()),"退款单已完成");
        refunds.setStatus(OrderEnum.PayStatus.SUCCEED.getCode());
        refunds.setTransactionId(transactionId);
        refunds.setRefundsFlowId(flowId);
        orderRefundsDao.updateByPrimaryKeySelective(refunds);
        if (StrUtil.isNotBlank(refunds.getNotifyMethod()) && !PaymentEnum.ALI_PAY.getCode().equals(refunds.getRefundsType())) {
            rabbitTemplate.convertAndSend(refunds.getNotifyMethod(), JSON.toJSONString(orderRefundsDao.selectByPrimaryKey(refundsId)));
        }

    }


    /**
     * 订单支付完成
     * @param orderPayId
     * @param transactionId
     * @param type
     */
    public void completePayment(String payAppId,String orderPayId, String transactionId, Integer type,String payFlowId){
        OrderPay orderPay = orderPayDao.getOrderPayByOrderId(orderPayId);
        //没找到订单跳过
        if(orderPay==null){
            log.error("未找到完成支付宝订单 orderId={}",orderPayId);
            return;
        }
      /*  if(orderPay!=null&&OrderEnum.PayStatus.SUCCEED.getCode().equals(orderPay.getTradeStatus())){
            log.warn("订单已经支付完成 orderPay={}", JSON.toJSONString(orderPay));
            return;
        }*/
        orderPayDao.completePayment(orderPay.getId(),payAppId,transactionId,type,payFlowId);
        if(StrUtil.isNotBlank(orderPay.getNotifyMethod())){
            rabbitTemplate.convertAndSend(orderPay.getNotifyMethod(),JSON.toJSONString(orderPayDao.getOrderPayByOrderId(orderPayId)));
        }
        redisService.getHashOps().increment(RedisKey.DATA_TODAY_CHART.getKey(), DataEnum.TodayData.PAYMENTS.name(), orderPay.getAmount().doubleValue());
    }
    @Transactional(rollbackFor = Exception.class)
    public String wxpay(FundsPaymentBo paymentBo){
        OrderPay orderPay = null;
        if(StrUtil.isNotBlank(paymentBo.getPayId())){
            orderPay = orderPayDao.selectByPrimaryKey(paymentBo.getPayId());
            ParamException.isNull(orderPay,"请输入正确的支付ID");

        }else if(StrUtil.isNotBlank(paymentBo.getOrderId())){
            orderPay = orderPayDao.getOrderPayByOrderId(paymentBo.getOrderId());
            if(orderPay==null){
                List<OrderPay>  orderPays = orderPayDao.getOrderPayByMasterId(paymentBo.getOrderId());
                ParamException.isTrue(CollectionUtils.isEmpty(orderPays),"订单号不正确");
                orderPay = BeanConverUtils.convertBean(createOrderPay(orderPays),OrderPay.class);
                ParamException.isNull(orderPay,"请输入正确的订单ID");
            }
        }
        ParamException.isTrue(OrderEnum.PayStatus.SUCCEED.getCode().equals(orderPay.getTradeStatus()),"订单已支付不要重复支付");
        orderPay.setPayUserId(paymentBo.getOperator());
        orderPay.setPayUserName(paymentBo.getOperatorName());
        orderPay.setPayProduct(paymentBo.getProduct());
        orderPay.setPayTimes(orderPay.getPayTimes()+1);
        orderPay.setTradeStatus(OrderEnum.PayStatus.PRE.getCode());
        orderPay.setPayOpenId(paymentBo.getOpenId());
        orderPay.setPayType(paymentBo.getPayType());
        orderPay.setPayAppId(paymentBo.getAppId());
        orderPayDao.updateByPrimaryKeySelective(orderPay);
        if(PaymentEnum.ALI_PAY.getCode().equals(paymentBo.getPayType())){
            return aliPayServer.aliPaymentSdk(orderPay);
        }else {
            OrderWxPay orderWxPay = wxPayServer.createWxPayOrder(orderPay);
            return JSON.toJSONString(wxPayServer.getWxPayInfoVo(orderWxPay));
        }
    }


    /**
     * 创建订单并且返回客户端需要的支付信息
     * @param orderPayBo
     * @return
     */
    public String payment(OrderPayBo orderPayBo){
        OrderPay orderPay = orderPayDao.getOrderPayByOrderId(orderPayBo.getOrderId());
        if(orderPay!=null){
            ParamException.isTrue(OrderEnum.PayStatus.SUCCEED.getCode().equals(orderPay.getTradeStatus()),"订单已支付不要重复支付");
        }else {
            orderPay = createOrderPay(orderPayBo);
        }
        orderPay.setExpirationTime(orderPayBo.getExpirationTime());
        orderPay.setPayUserId(orderPayBo.getPayUserId());
        orderPay.setPayUserName(orderPayBo.getPayUserName());
        orderPay.setPayProduct(orderPayBo.getPayProduct());
        orderPay.setPayTimes(orderPay.getPayTimes()+1);
        orderPay.setTradeStatus(OrderEnum.PayStatus.PRE.getCode());
        orderPay.setPayOpenId(orderPayBo.getPayOpenId());
        orderPay.setPayType(orderPayBo.getPaymentType());
        orderPay.setPayAppId(orderPayBo.getPayAppId());
        orderPayDao.updateByPrimaryKeySelective(orderPay);
        if(PaymentEnum.ALI_PAY.getCode().equals(orderPay.getPayType())){
            return aliPayServer.aliPaymentSdk(orderPay);
        }else if(PaymentEnum.WX.getCode().equals(orderPay.getPayType())){
            OrderWxPay orderWxPay = wxPayServer.createWxPayOrder(orderPay);
            return JSON.toJSONString(wxPayServer.getWxPayInfoVo(orderWxPay));
        }else{
            ByteDanceOrderVo payOrder = byteDanceServer.createPayOrder(orderPay);
            ParamException.isFalse(Integer.valueOf(0).equals(payOrder.getErr_no()),payOrder.getErr_tips());
            return JSON.toJSONString(payOrder.getData());
        }
    }

}
